#   Copyright (C) 2008      Tri Tech Information Systems Inc.
# 
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
# 
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
# 
#   You should have received a copy of the GNU General Public License along
#   with this program; if not, write to the Free Software Foundation, Inc.,
#   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#   
from callable import MethodWrapper
from formatters import generator, formatter, argument_list
from parser import CodeModel

class VirtualMethodWrapper( MethodWrapper ):
    TEMPLATE_OVERLOAD = '''
    virtual %(returnType)s %(name)s(%(params)s) %(maybeConst)s
    {
        PythonGIL gil;
        try
        {
            %(interface_impl)s
        }
        catch(boost::python::error_already_set &)
        {
            throw python_error::raise();
        }
    }


    %(returnType)s __default__%(name)s(%(params)s) %(maybeConst)s
    {
        %(default_interface_impl)s

        %(final_case)s
    }

    '''


    def __init__( self, wrapper, final_parent):

        assert wrapper.item.isVirtual
        # deliberately not calling parent constructor
        self.final_parent = final_parent
        self.item = wrapper
        # The upshot of this is that any attributes not found
        # will be looked for in the wrapper object
        # thus it if we don't deliberately change something
        # it will act like the underlying function being wrapped

        self.interface_impl_override = """
            if( override fn = this->get_override( %(quotedName)s ) )
                %(return_fn)s
            else
                return __default__%(name)s(%(param_values)s);
        """
        self.default_interface_impl = ""

    def reparent(self, new_parent):
        """
        Return an instance of this class which is the same
        except has a different final_parent
        """
        obj = VirtualMethodWrapper.__new__(self.__class__)
        obj.__dict__.update(self.__dict__)
        obj.final_parent = new_parent
        return obj


    def generate_interfaceFunctionType(self):        
        if self.isConstant:
            return "(%(returnType)s (Wrap_%(final_parent.name)s::*)(%(argumentList)s) const)"
        else:
            return "(%(returnType)s (Wrap_%(final_parent.name)s::*)(%(argumentList)s))"

    def function_pointer(self):
        """
        If we inherit a protected function.
        We cannot (portably) obtain a pointer to it.
        However, we can obtain a pointer to our re-implementation of it.
        """
        if self.item.accessPolicy == CodeModel.AccessPolicy.Protected:
            return None
        else:
            return MethodWrapper.function_pointer(self)

    def default_implementation(self):
        return "%(interfaceFunctionType)s&Wrap_%(final_parent.name)s::__default__%(name)s"


    def generate_return_fn(self):
        if self.returnType == 'void':
            return 'fn(%(pyparam_values)s);'
        else:
            return """
            {
                bpy::object result = fn(%(pyparam_values)s);
                bpy::extract< %(returnType)s > extractor( result );
                %(returnType)s ret = extractor();
                return ret;
            }
            """

    @generator
    def generate_final_case(self):
        """
        At this point in time, we've given up on trying to locate 
        an implementation
        """

        if self.isAbstract:
            # all is lost, this is a pure virtual method
            return "throw pure_virtual_call_error(self(), %(quotedName)s);"
        else:
            return "return %(final_parent.qualifiedName)s::%(name)s(%(param_values)s);"

    def replace(self, code):
        self.interface_impl_override = code

    def replaceDefault(self, code):
        self.default_interface_impl = code
            
    @generator
    def generate_interface_impl(self):
        return self.interface_impl_override
 
    @generator
    def generate_functionExpr(self):
        return "%(final_parent.qualifiedName)s::%(name)s"

    def generate_functionTypeClassName(self):
        return self.final_parent.qualifiedName
